// Created by Windward Studios - no copyright is claimed. This code can be used in
// any manner by anyone for any reason. There is no copyright of any kind on it. You may
// use it in commercial products. You may change it without sharing those changes.
// We ask that you keep the "created by Windward Studios" in a comment at the top.

using System;
using System.Collections;
using System.Collections.Specialized;
using System.Configuration;
using System.Data;
using System.Data.Common;

namespace net.windward.utils.ado.SqlServer
{
	/// <summary>
	/// An instance of a SqlServer running on a computer.
	/// </summary>
	public class WrSqlServerServer : IWrServer
	{
		private readonly DbProviderFactory provider;
		private readonly IWrSyntax syntax;
		private readonly string name;

		private static readonly int debugDelaySeconds = -1;

		static WrSqlServerServer()
		{

			NameValueCollection appSettings = ConfigurationManager.AppSettings;
			string str = appSettings["select-delay"];
			if (string.IsNullOrEmpty(str))
				return;

			int num;
			if (int.TryParse(str, out num))
				if ((0 < num) && (num < 120))
					debugDelaySeconds = num;
		}

		/// <summary>
		/// Create a SqlServer server object.
		/// </summary>
		/// <param name="provider">The provider for this server.</param>
		/// <param name="name">The name of the server.</param>
		public WrSqlServerServer(DbProviderFactory provider, string name)
		{
			this.provider = provider;
			syntax = new WrSqlServerSyntax();
			this.name = name;
		}

		/// <summary>
		/// The name of the server.
		/// </summary>
		public string Name
		{
			get { return name; }
		}

		/// <summary>
		/// All databases on this server. If a provider does not have the concept of databases (Oracle)
		/// it will always return 1 database.
		/// </summary>
		/// <param name="credentials">The user credentials to access the database.</param>
		/// <returns>All databases on this server.</returns>
		public IWrDatabase[] GetDatabases(WrCredentials credentials)
		{
			return GetDatabases(WrSqlServerVendor.ConnectionString(provider, name, "master", credentials, true));
		}

		/// <summary>
		/// All databases on this server.
		/// </summary>
		/// <param name="connStr">The connection string to access the database.</param>
		/// <returns>All databases on this server.</returns>
		public IWrDatabase[] GetDatabases(string connStr)
		{

			DebugPause();

			ArrayList rtn = new ArrayList();
			using (IDbConnection sc = provider.CreateConnection())
			{
				sc.ConnectionString = connStr;
				sc.Open();
				// we try SELECT NAME FROM sysdatabases first. If that doesn't work we do EXEC sp_databases
				try
				{
					using (IDbCommand cmd = sc.CreateCommand())
					{
						cmd.CommandText = "SELECT NAME FROM master..sysdatabases";

						using (IDataReader myReader = cmd.ExecuteReader())
						{
							while (myReader.Read())
							{
								string dbName = myReader.GetString(0).Trim();
								if (dbName.Length > 0)
									rtn.Add(new WrSqlServerDatabase(provider, name, dbName));
							}
						}
					}
				}
				catch (Exception)
				{
					// nada
				}

				if (rtn.Count == 0)
					using (IDbCommand cmd = sc.CreateCommand())
					{
						cmd.CommandType = CommandType.StoredProcedure;
						cmd.CommandText = "sp_databases";

						using (IDataReader myReader = cmd.ExecuteReader())
						{
							while (myReader.Read())
							{
								string dbName = myReader.GetString(0).Trim();
								if (dbName.Length > 0)
									rtn.Add(new WrSqlServerDatabase(provider, name, dbName));
							}
						}
					}
			}

			rtn.Sort();
			return (WrSqlServerDatabase[]) rtn.ToArray(typeof (WrSqlServerDatabase));
		}

		// can add a pause on each select in debug mode
		private static void DebugPause()
		{

#if DEBUG
			if (debugDelaySeconds > 0)
				System.Threading.Thread.Sleep(debugDelaySeconds * 1000);
#endif
		}

		#region IWrServer Members

		/// <summary>
		/// Create a database object.
		/// </summary>
		/// <param name="database">The name of the database.</param>
		public IWrDatabase CreateDatabase(string database)
		{
			return new WrSqlServerDatabase(provider, name, database);
		}

		#endregion

		#region Implementation of IComparable

		/// <summary>
		/// Compares the current instance with another object of the same type.
		/// </summary>
		/// <param name="obj">An object to compare with this instance. </param>
		/// <returns>a 32-bit signed integer that indicates the relative order of the objects being compared.</returns>
		public int CompareTo(object obj)
		{
			WrSqlServerServer db = obj as WrSqlServerServer;
			if (db == null)
				return 1;
			return name.CompareTo(db.name);
		}

		#endregion
	}
}
